package br.usp.ime.ingpos.testes.services;

import java.util.Date;
import java.util.List;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;

import br.com.caelum.vraptor.util.test.MockLocalization;
import br.usp.ime.ingpos.modelo.Candidato;
import br.usp.ime.ingpos.modelo.CartaDeRecomendacao;
import br.usp.ime.ingpos.modelo.Email;
import br.usp.ime.ingpos.modelo.Inscricao;
import br.usp.ime.ingpos.modelo.ProcessoSeletivo;
import br.usp.ime.ingpos.modelo.Usuario;
import br.usp.ime.ingpos.modelo.dao.AreaDePesquisaDAO;
import br.usp.ime.ingpos.modelo.dao.CandidatoDAO;
import br.usp.ime.ingpos.modelo.dao.CartaDeRecomendacaoDAO;
import br.usp.ime.ingpos.modelo.dao.InscricaoDAO;
import br.usp.ime.ingpos.modelo.dao.OrientadorDAO;
import br.usp.ime.ingpos.modelo.dao.PerfilDao;
import br.usp.ime.ingpos.modelo.dao.ProcessoSeletivoDao;
import br.usp.ime.ingpos.modelo.dao.UsuarioDao;
import br.usp.ime.ingpos.seguranca.Criptografia;
import br.usp.ime.ingpos.services.CandidatoService;
import br.usp.ime.ingpos.services.CartaDeRecomendacaoService;
import br.usp.ime.ingpos.services.EmailException;
import br.usp.ime.ingpos.services.EmailService;
import br.usp.ime.ingpos.services.InscricaoService;
import br.usp.ime.ingpos.services.OrientadorService;
import br.usp.ime.ingpos.services.ProcessoSeletivoService;
import br.usp.ime.ingpos.services.UsuarioService;
import br.usp.ime.ingpos.testes.BancoDeDadosTestCase;
import br.usp.ime.ingpos.web.controllers.UsuarioSessao;

public class CartaDeRecomendacaoServiceTeste
    extends
        BancoDeDadosTestCase
{

    private UsuarioService usuarioService;
    private EmailService emailService;
    private Email email;
    private Usuario usuario;
    private UsuarioSessao usuarioSessao;
    private InscricaoService inscricaoService;
    private CartaDeRecomendacaoService cartaDeRecomendacaoService;
    private InscricaoDAO inscricaoDao;
    private ProcessoSeletivo processoSeletivo;

    public CartaDeRecomendacaoServiceTeste(
        String name )
    {
        super( name );
    }

    @Before
    protected void setUp()
        throws Exception
    {
        super.setUp();

        usuarioService = new UsuarioService(
            new UsuarioDao( getSessionCreator() ),
            new UsuarioSessao() );
        assertNotNull( usuarioService );
        emailService = Mockito.mock( EmailService.class );
        email = Mockito.mock( Email.class );
        
        usuario = usuarioService.procurarPorEmail( RegistroNovoUsuarioServiceTeste.EMAIL );
        assertNotNull( usuario );
        usuarioSessao = new UsuarioSessao();
        assertNotNull( usuarioSessao );
        usuarioSessao.setUsuario( usuario );

        inscricaoService = new InscricaoService( usuarioSessao, usuarioService, new InscricaoDAO(
            getSessionCreator() ), new CandidatoService(
            usuarioSessao,
            usuarioService,
            new CandidatoDAO( getSessionCreator() ),
            emailService,
            new MockLocalization() ), new ProcessoSeletivoService( new ProcessoSeletivoDao(
            getSessionCreator() ), emailService, new MockLocalization() ), new OrientadorService(
            new OrientadorDAO( getSessionCreator() ),
            new AreaDePesquisaDAO( getSessionCreator() ),
            new PerfilDao( getSessionCreator() ) ) );

        final ProcessoSeletivoService processoSeletivoService = new ProcessoSeletivoService(
            new ProcessoSeletivoDao(getSessionCreator() ), emailService, new MockLocalization() );
        assertNotNull( processoSeletivoService );
        List<ProcessoSeletivo> processosSeletivos = processoSeletivoService.buscarProcessosSeletivosPorData( new Date() );
        assertFalse( processosSeletivos.isEmpty() );
        processoSeletivo = processosSeletivos.get( 0 );
        
        inscricaoDao = new InscricaoDAO( getSessionCreator() );
        Inscricao inscricao = inscricaoDao.procurarPorCandidatoEProcessoSeletivo( (Candidato) usuario, processoSeletivo );
        if( inscricao == null ) {
            inscricao = new Inscricao();
        }
        inscricao.setCandidato( (Candidato) usuario );
        assertNotNull( inscricao.getCandidato() );

        inscricao.setProcessoSeletivo( processoSeletivo );
        assertNotNull( inscricao.getProcessoSeletivo() );
        
        inscricaoDao.saveOrUpdate( inscricao );
        ((Candidato) usuario).insereInscricao( inscricao );
        
        // TODO Tem que colocar uma inscrição para o Usuario
        inscricaoService.inserirOuAtualizarInscricao( inscricao );

        cartaDeRecomendacaoService = new CartaDeRecomendacaoService(
            new CartaDeRecomendacaoDAO( getSessionCreator() ),
            usuarioSessao,
            emailService,
            inscricaoService,
            null,
            new MockLocalization() );
    }

    @Test
    public void testSolicitarRecomendacao()
    {
        Mockito.when( emailService.construirEmail( Mockito.anyString(), Mockito.anyString(), Mockito.anyString() ) ).thenReturn( email );
        
        final CartaDeRecomendacao cartaDeRecomendacao = new CartaDeRecomendacao();

        cartaDeRecomendacao.setUsuario( usuario );
        cartaDeRecomendacao.setNome( "Professor Alfredo" );
        cartaDeRecomendacao.setInstituicao( "IME" );
        cartaDeRecomendacao.setEmail( RegistroNovoUsuarioServiceTeste.EMAIL2 );
        cartaDeRecomendacaoService.solicitarRecomendacao( cartaDeRecomendacao );

        String hash = Criptografia.md5( cartaDeRecomendacao.getEmail() + usuario.getEmail() );
        CartaDeRecomendacao cartasDeRecomendacaoExistente = cartaDeRecomendacaoService.procurarPorHash( hash );
        Assert.assertNotNull( cartasDeRecomendacaoExistente );

        Assert.assertEquals( cartaDeRecomendacao.getEmail(),
            cartasDeRecomendacaoExistente.getEmail() );
        Assert.assertEquals( cartaDeRecomendacao.getNome(), cartasDeRecomendacaoExistente.getNome() );
        Assert.assertEquals( cartaDeRecomendacao.getUsuario(),
            cartasDeRecomendacaoExistente.getUsuario() );

        Mockito.verify( emailService ).construirEmail( Mockito.anyString(), Mockito.anyString(), Mockito.anyString() );
        try {
            Mockito.verify( emailService ).enviarEmail( email );
        } catch( EmailException e ) {
            assertTrue( false );
            e.printStackTrace();
        }
    }

    @Test
    public void testProcurarCartasDeRecomendacaoPorUsuario()
    {
        List<CartaDeRecomendacao> cartas = cartaDeRecomendacaoService.procurarPorUsuario( usuario );
        assertNotNull( cartas );
        assertNotNull( cartas.size() > 0 );
    }

    @Test
    public void testReenviarCartaDeRecomendacao()
    {
        Mockito.when( emailService.construirEmail( Mockito.anyString(), Mockito.anyString(), Mockito.anyString() ) ).thenReturn( email );
        final List<CartaDeRecomendacao> cartas = cartaDeRecomendacaoService.procurarPorUsuario( usuario );

        assertNotNull( cartas );
        assertTrue( cartas.size() > 0 );

        cartaDeRecomendacaoService.reenviarRecomendacao( cartas.get( 0 ) );
        
        Mockito.verify( emailService ).construirEmail( Mockito.anyString(), Mockito.anyString(), Mockito.anyString() );
        try {
            Mockito.verify( emailService ).enviarEmail( email );
        } catch( EmailException e ) {
            assertTrue( false );
            e.printStackTrace();
        }
    }
}
